package com.hmall.common.utils;

import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * Cookie构建工具类
 * 功能：封装Cookie的创建、编码、解码逻辑，支持中文处理和跨域配置
 * 设计模式：建造者模式（Builder Pattern）
 */
@Slf4j
@Data
@Accessors(chain = true, fluent = true)
public class CookieBuilder {
    /** 字符编码（默认UTF-8） */
    private Charset charset = StandardCharsets.UTF_8;
    /** 过期时间（秒），-1表示浏览器关闭时过期 */
    private int maxAge = -1;
    /** 有效路径（默认根路径） */
    private String path = "/";
    /** 是否仅HTTP访问（防止XSS攻击） */
    private boolean httpOnly;
    /** Cookie名称 */
    private String name;
    /** Cookie值 */
    private String value;
    /** 有效域名（如 .example.com） */
    private String domain;
    /** HTTP请求对象（用于自动获取域名） */
    private final HttpServletRequest request;
    /** HTTP响应对象（用于写入Cookie） */
    private final HttpServletResponse response;

    /**
     * 构造函数
     * @param request HTTP请求对象
     * @param response HTTP响应对象
     */
    public CookieBuilder(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    /**
     * 构建并写入Cookie到响应
     * 自动处理：
     * 1. 对Cookie值进行URL编码（防止中文乱码）
     * 2. 自动生成域名（若无手动设置）
     * 3. 记录Cookie配置信息
     */
    public void build() {
        // 响应对象为空时直接返回（避免NPE）
        if (response == null) {
            log.error("response为null，无法写入cookie");
            return;
        }

        // 1. 创建Cookie对象并编码值
        Cookie cookie = new Cookie(name, URLEncoder.encode(value, charset));

        // 2. 配置域名（优先级：手动设置 > 请求获取 > 不设置）
        if (StrUtil.isNotBlank(domain)) {
            cookie.setDomain(domain);
        } else if (request != null) {
            // 从请求中提取域名（如 example.com -> .example.com）
            String serverName = request.getServerName();
            serverName = StrUtil.subAfter(serverName, ".", false);
            cookie.setDomain("." + serverName);
        }

        // 3. 配置其他属性
        cookie.setHttpOnly(httpOnly);
        cookie.setMaxAge(maxAge);
        cookie.setPath(path);

        // 4. 记录Cookie信息（调试用）
        log.debug("生成cookie，编码方式:{}，【{}={}，domain:{};maxAge={};path={};httpOnly={}】",
                charset.name(), name, value, domain, maxAge, path, httpOnly);

        // 5. 写入响应
        response.addCookie(cookie);
    }

    /**
     * 解码Cookie值（处理中文乱码）
     * @param cookieValue 编码后的Cookie值
     * @return 解码后的原始值
     */
    public String decode(String cookieValue) {
        return URLDecoder.decode(cookieValue, charset);
    }
}